//定义drawTopo类
function DrawTopo(topoData, sceneWidth, sceneHeight, minWidth, padding) {
    this.topoData = topoData;
    this.sceneWidth = sceneWidth;
    this.sceneHeight = sceneHeight;
    this.minWidth = minWidth;
    this.padding = padding;
    this.nodePosition = {};

    this.width = this.sceneWidth - this.padding * 2;
    this.height = this.sceneHeight - this.padding * 2;
    this.svg = {};
}

DrawTopo.prototype.initSVG = function() {
    //定义去掉留白后真实的作画范围
    this.width = this.sceneWidth - this.padding * 2;
    this.height = this.sceneHeight - this.padding * 2;
    //添加svg元素，并设置svg的属性和样式
    this.svg = d3.select("#topoDisplay").append("svg");
    this.svg.attr("width",this.sceneWidth)
            .attr("height",this.sceneHeight);

    this.svg.style("margin", "0")
            .style("overflow", "auto");
};

DrawTopo.prototype.drawL2Topo = function() {
    var numSw_first = this.topoData.topoInfo.numsw_bottom;//取出一层交换机数目
    var numSw_second = this.topoData.topoInfo.numsw_top;//取出二层交换机数目
    var hosts = this.topoData.topoInfo.numhost;

    var timesHost = 4;
    var timesGroup = 4;
    
    var groups = numSw_first;
    var hostsInGroup = hosts/groups;

    var hostRadius_calc = this.width/(timesHost*groups*hostsInGroup - groups*timesHost + groups*timesGroup - timesGroup + 2);
    var hostRadius = hostRadius_calc < this.minWidth ? this.minWidth : hostRadius_calc;

    var hostPadding = timesHost * hostRadius;
    var groupPadding = timesGroup * hostRadius;

    var xStart = this.padding + hostRadius;
    var yStart = this.height - hostRadius + this.padding;

    //绘制主机
    for(var i = 0; i < hosts; i++) {
        var cx = xStart + (i % hostsInGroup) * hostPadding + Math.floor(i / hostsInGroup) * ((hostsInGroup - 1) * hostPadding + groupPadding) ;
        var cy = yStart;
        var hostId = "" + i;
        
        this.svg.append("circle")
                .attr("id", hostId)
                .attr("fill","steelblue")
                .attr("r",hostRadius) 
                .attr("cx",cx)
                .attr("cy",cy);

        //节点位置存入nodePosition中
        this.nodePosition[hostId] = {
            x: cx,
            y: cy
        };
    }

    //给控制器加上不同的背景颜色
    var controller = document.getElementById("" + this.topoData.topoInfo.controller);
    controller.setAttribute("fill", "red");

    //绘制第一层交换机
    var rectW = 3 * hostRadius;
    var rectH = 2 * hostRadius;
    var rectCenterXstart = xStart + (hostsInGroup - 1) * hostPadding/2;


    for(var j = 0;j < numSw_first; j++) {

        var rectCenterX = rectCenterXstart + (j % groups) * ( groupPadding + (hostsInGroup - 1) * hostPadding);
        
        var rectCenterY = yStart - this.height/2 + 2 * hostRadius;
        var swId = j + hosts; 
        this.svg.append("rect")
                .attr("id", "" + swId)
                .attr("fill","steelblue")
                .attr("x", rectCenterX - rectW/2)
                .attr("y", rectCenterY - rectH/2)
                .attr("width", rectW)
                .attr("height", rectH);

        //节点位置存入nodePosition中
        this.nodePosition[swId] = {
            x: rectCenterX,
            y: rectCenterY
        };
    }

    //绘制第二层交换机
    var rectCenterEnd;
    if(numSw_first === numSw_second) {
      rectCenterXstart = this.nodePosition[hosts].x;
      rectCenterEnd = this.nodePosition[hosts + numSw_first - 1].x;
    }
    else {
      rectCenterXstart = this.nodePosition[hosts].x + rectW/2;
      rectCenterEnd = this.nodePosition[hosts + numSw_first - 1].x - rectW/2;
    }

    var rectPadding = (rectCenterEnd - rectCenterXstart)/(numSw_second - 1);
    for(var m = 0; m < numSw_second; m++) {
        var swSecondId = numSw_first + hosts + m;
        var rectCenterX_2 = rectCenterXstart + m * rectPadding;
        var rectCenterY_2 = this.padding + rectH/2;

        this.svg.append("rect")
                .attr("id", "" + swSecondId)
                .attr("fill", "steelblue")
                .attr("x", rectCenterX_2 - rectW/2)
                .attr("y", rectCenterY_2 - rectH/2)
                .attr("width", rectW)
                .attr("height", rectH);

        this.nodePosition[swSecondId] = {
            x: rectCenterX_2,
            y: rectCenterY_2
        };
    }

    //绘制直线
    var links = this.topoData.links;
    for(var k = 0; k < links.length; k++ ) {
        var sx = this.nodePosition[links[k].s].x;
        var sy = this.nodePosition[links[k].s].y;

        var dx = this.nodePosition[links[k].d].x;
        var dy = this.nodePosition[links[k].d].y;

        this.svg.append("line")
                .attr("id", "l" + k)
                .attr("stroke", "steelblue")
                .attr("stroke-width", "1")
                .attr("x1", sx)
                .attr("x2", dx)
                .attr("y1", sy)
                .attr("y2", dy);
    }

    //添加节点编号
    for(var l = 0; l < hosts + numSw_first + numSw_second; l++) {
        var delx;
        if(l >= 10) {
            delx = -9;
        }
        else{
            delx = -5;
        }
        var text_x = this.nodePosition[l].x + delx;
        var text_y = this.nodePosition[l].y + 6;
        this.svg.append("text")
                .attr("x", text_x)
                .attr("y", text_y)
                .attr("fill", "white")
                .text("" + l);
    }
};

DrawTopo.prototype.drawL3Topo = function() {
    //定义作图需要的变量
    var numSw = this.topoData.topoInfo.numpod * this.topoData.topoInfo.numswpod;
    var hosts = this.topoData.topoInfo.numhost;
    var cores = this.topoData.topoInfo.numcoresw;

    var timesHost = 4;
    var timesGroup = 4;
    
    var groups = numSw/2;
    var hostsInGroup = hosts/groups;

    var hostRadius_calc = this.width/(timesHost*groups*hostsInGroup - groups*timesHost + groups*timesGroup - timesGroup + 2);
    var hostRadius = hostRadius_calc < this.minWidth ? this.minWidth : hostRadius_calc;

    var hostPadding = timesHost * hostRadius ;
    var groupPadding = timesGroup * hostRadius;

    var xStart = this.padding + hostRadius;
    var yStart = this.height - hostRadius + this.padding;

    //绘制主机
    for(var i = 0; i < hosts; i++) {
        var cx = xStart + (i % hostsInGroup) * hostPadding + Math.floor(i / hostsInGroup) * ((hostsInGroup - 1) * hostPadding + groupPadding);
        var cy = yStart;
        var hostId = "" + i;
        
        this.svg.append("circle")
                .attr("id", hostId)
                .attr("fill","steelblue")
                .attr("r",hostRadius) 
                .attr("cx",cx)
                .attr("cy",cy);

        //节点位置存入nodePosition中
        this.nodePosition[hostId] = {
            x: cx,
            y: cy
        };
    }

    //给控制器加上不同的背景颜色
    var controller = document.getElementById("" + this.topoData.topoInfo.controller);
    
    controller.setAttribute("fill", "red");

    //绘制POD
    var rectW = 3 * hostRadius;
    var rectH = 2 * hostRadius;
    var rectCenterXstart = xStart + (hostsInGroup - 1) * hostPadding/2;

    for(var j = 0;j < numSw; j++) {

        var rectCenterX = rectCenterXstart + (j % groups) * ( groupPadding + (hostsInGroup - 1) * hostPadding);
        
        var rectCenterY = yStart - (Math.floor(j / groups) + 1) * this.height/3 + 2 * hostRadius;
        var swId = j + hosts; 
        this.svg.append("rect")
                .attr("id", "" + swId)
                .attr("fill","steelblue")
                .attr("x", rectCenterX - rectW/2)
                .attr("y", rectCenterY - rectH/2)
                .attr("width", rectW)
                .attr("height", rectH);

        //节点位置存入nodePosition中
        this.nodePosition[swId] = {
            x: rectCenterX,
            y: rectCenterY
        };
    }

    //绘制核心交换机
    var coreRadius = 1.5 * hostRadius;
    var coreStart = this.nodePosition[hosts].x + coreRadius;
    var coreEnd = this.nodePosition[hosts + numSw - 1].x - coreRadius;

    var corePadding = (coreEnd - coreStart)/(cores - 1);
    for(var m = 0; m < cores; m++) {
        var coreId = numSw + hosts + m;
        var coreX = coreStart + m * corePadding;
        var coreY = this.padding + coreRadius;

        this.svg.append("circle")
                .attr("id", "" + coreId)
                .attr("fill", "steelblue")
                .attr("cx", coreX)
                .attr("cy", coreY)
                .attr("r", coreRadius);

        this.nodePosition[coreId] = {
            x: coreX,
            y: coreY
        };
    }

    //绘制直线
    var links = this.topoData.links;
    for(var k = 0; k < links.length; k++ ) {
        var sx = this.nodePosition[links[k].s].x;
        var sy = this.nodePosition[links[k].s].y;

        var dx = this.nodePosition[links[k].d].x;
        var dy = this.nodePosition[links[k].d].y;

        this.svg.append("line")
                .attr("id", "l" + k)
                .attr("stroke", "steelblue")
                .attr("stroke-width", "1")
                .attr("x1", sx)
                .attr("x2", dx)
                .attr("y1", sy)
                .attr("y2", dy);
    }

    //添加节点编号
    for(var l = 0; l < hosts + numSw + cores; l++) {
        var delx;
        if(l >= 10) {
            delx = -9;
        }
        else{
            delx = -5;
        }
        var text_x = this.nodePosition[l].x + delx;
        var text_y = this.nodePosition[l].y + 6;
        this.svg.append("text")
                .attr("x", text_x)
                .attr("y", text_y)
                .attr("fill", "white")
                .text("" + l);
      }
};

DrawTopo.prototype.moveLinks = function() {
  $("line").insertBefore($("#0"));
};

window.addEventListener("load", function() {
  //取得界面上拓扑展示窗口的大小
    var topoWindow = document.getElementById("topoDisplay");
    var topoRect = topoWindow.getBoundingClientRect();

    var minWidth = 10;
    var padding = 20;

    var sceneWidth = topoRect.width || (topoRect.right - topoRect.left);
    var sceneHeight = topoRect.height || (topoRect.bottom - topoRect.top);

    console.log(sceneHeight);

    //发Ajax请求，得到topoData的数据
    var xhr = new XMLHttpRequest();

    xhr.addEventListener("readystatechange",function() {
      if(xhr.readyState === 4) {
          if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
              var topoData = JSON.parse(xhr.responseText);
              var layer = topoData.topoInfo.layer;

              console.log("received topoData succesfully");
              var topo = new DrawTopo(topoData, sceneWidth, sceneHeight, minWidth, padding);

              topo.initSVG();
              
              if(layer === 2){
                  topo.drawL2Topo(topoData);
                  topo.moveLinks();
              }
              else if(layer === 3){
                  topo.drawL3Topo(topoData);
                  topo.moveLinks();
              }
              else {
                  console.log("layer is beyond 3,have no idea to draw it");
              }
          }
          else {
            console.log("failed to request for topoData");
          }
      }
    });

    xhr.open("get", "/topoData", "true");
    xhr.send(null);
});

